package com.motong.gongdan.service;

import cn.hutool.core.date.DateField;
import cn.hutool.core.date.DateUnit;
import cn.hutool.core.date.DateUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.motong.gongdan.constant.CommonConstant;
import com.motong.gongdan.entity.DeviceInfo;
import com.motong.gongdan.entity.DeviceProduceLog;
import com.motong.gongdan.mapper.DeviceProduceLogMapper;
import com.motong.gongdan.vo.H5Vo.device.query.CountDashboardQuery;
import com.motong.gongdan.vo.H5Vo.device.vo.CountDashboardVo;
import com.motong.gongdan.vo.system.device.query.DeviceListQuery;
import com.motong.gongdan.vo.system.device.vo.CountReportVo;
import com.motong.gongdan.vo.system.device.vo.DeviceListVo;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors;

@Service
public class DeviceProduceLogService extends ServiceImpl<DeviceProduceLogMapper, DeviceProduceLog> {

    @Resource
    private DeviceInfoService deviceInfoService;

    @Resource
    private DeviceProduceLogMapper deviceProduceLogMapper;

    @Resource
    private RedisTemplate<String, Object> redisTemplate;

    @Resource
    private DeviceStatusService deviceStatusService;

    public Page<CountDashboardVo> countDashboard(Page<DeviceInfo> page, CountDashboardQuery query, String cacheNamePrefix) {
        Page<DeviceListVo> deviceData = deviceInfoService.getList(page, new DeviceListQuery().setGroupId(query.getGroupId()).setDeviceId(query.getDeviceId()));
        List<Long> deviceIds = new ArrayList<>();
        Page<CountDashboardVo> data = new Page<CountDashboardVo>().setTotal(deviceData.getTotal())
                .setRecords(deviceData.getRecords().stream()
                        .map(i -> {
                            query.setStartTime(Optional.ofNullable(query.getStartTime()).orElse(DateUtil.beginOfDay(new Date()).offset(DateField.HOUR, 8)));
                            CountDashboardVo countDashboardVo = new CountDashboardVo().setDeviceSn(i.getDeviceSn()).setDeviceId(i.getId())
                                    .setDeviceName(i.getDeviceName()).setStatus(i.getStatus()).setStartTime(query.getStartTime());
                            if (Objects.nonNull(i.getStatus())) {
                                switch (i.getStatus()) {
                                    case 0:
                                        countDashboardVo.setStatusName("关机");
                                        break;
                                    case 1:
                                        countDashboardVo.setStatusName("运行");
                                        break;
                                    case 2:
                                        countDashboardVo.setStatusName("等待");
                                        break;
                                    case 3:
                                        countDashboardVo.setStatusName("故障");
                                        break;
                                    case 4:
                                        countDashboardVo.setStatusName("离线");
                                        break;
                                }
                            }
                            deviceIds.add(i.getId());
                            return countDashboardVo;
                        }).collect(Collectors.toList()));
        if (!CollectionUtils.isEmpty(deviceIds)) {
            List<Long> defaultDeviceCondition = Collections.synchronizedList(new ArrayList<>());
            Map<Long, CountDashboardVo> deviceIdDataMap = new HashMap<>(deviceIds.size());
            // 开启多线程处理
            int size = deviceIds.size();
            int everySize = size / 8;
            int lastSize = size % 8;
            CompletableFuture<?>[] futures = new CompletableFuture<?>[8];
            for (int d = 1; d <= 8; d++) {
                int startIndex = everySize * (d - 1);
                int endIndex = startIndex + everySize - 1;
                if (d == 8) {
                    endIndex = startIndex + everySize - 1 + lastSize;
                }
                int finalEndIndex = endIndex;
                CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {
                    List<Long> tempIds = deviceIds.subList(startIndex, finalEndIndex);
                    if (!CollectionUtils.isEmpty(tempIds)) {
                        tempIds.forEach(i -> {
                            Object condition = redisTemplate.opsForHash().get(CommonConstant.SEARCH_CONDITION_HASH_KEY, cacheNamePrefix + i);
                            // 区分设没设置自定义查询条件
                            if (Objects.nonNull(condition)) {
                                CountDashboardQuery cacheCondition = JSONUtil.toBean(condition.toString(), CountDashboardQuery.class);
                                CountDashboardQuery newCacheCondition = new CountDashboardQuery();
                                if (Objects.nonNull(cacheCondition.getStartTime())) {
                                    if (!DateUtil.isSameDay(cacheCondition.getStartTime(), new Date())) {
                                        cacheCondition.setStartTime(query.getStartTime());
                                    }
                                }
                                CountDashboardQuery cusQuery = newCacheCondition
                                        .setStartTime(Optional.ofNullable(cacheCondition.getStartTime()).orElse(query.getStartTime()))
                                        .setNumberPulses(Optional.ofNullable(cacheCondition.getNumberPulses()).orElse(query.getNumberPulses()))
                                        .setDeviceId(i).setStartSecond(query.getStartSecond()).setEndSecond(query.getEndSecond());
                                List<CountDashboardVo> countDashboardVos = deviceProduceLogMapper.countDashboard(cusQuery);
                                // 整合自定义查询数据
                                deviceIdDataMap.put(i, new CountDashboardVo().setTotalNum(0L).setNumOfHour(0L).setStartTime(cusQuery.getStartTime()).setNumberPulses(cusQuery.getNumberPulses()));
                                if (Objects.nonNull(countDashboardVos) && countDashboardVos.size() == 1) {
                                    long hours = DateUtil.between(cusQuery.getStartTime(), cusQuery.getEndTime(), DateUnit.HOUR);
                                    CountDashboardVo countDashboardVo = countDashboardVos.get(0).setNumberPulses(cusQuery.getNumberPulses()).setStartTime(cusQuery.getStartTime());
                                    if (countDashboardVo.getNumberPulses() == 0) {
                                        countDashboardVo.setNumberPulses(0).setTotalNum(0L);
                                    } else {
                                        countDashboardVo.setTotalNum(countDashboardVo.getTotalNum() * countDashboardVo.getNumberPulses());
                                        countDashboardVo.setNumOfHour(hours == 0 ? 0L : countDashboardVo.getTotalNum() / hours);
                                    }
                                    deviceIdDataMap.put(i, countDashboardVo);
                                }
                            } else {
                                defaultDeviceCondition.add(i);
                            }
                        });
                    }
                });
                futures[d - 1] = future;
            }
            try {
                CompletableFuture.allOf(futures).get();
            } catch (Exception e) {
                log.error("线程分段处理出现异常!");
            }


//            deviceIds.forEach(i -> {
//                Object condition = redisTemplate.opsForHash().get(CommonConstant.SEARCH_CONDITION_HASH_KEY, cacheNamePrefix + i);
//                // 区分设没设置自定义查询条件
//                if (Objects.nonNull(condition)) {
//                    CountDashboardQuery cacheCondition = JSONUtil.toBean(condition.toString(), CountDashboardQuery.class);
//                    CountDashboardQuery newCacheCondition = new CountDashboardQuery();
//                    if (Objects.nonNull(cacheCondition.getStartTime())) {
//                        if (!DateUtil.isSameDay(cacheCondition.getStartTime(), new Date())) {
//                            cacheCondition.setStartTime(query.getStartTime());
//                        }
//                    }
//                    CountDashboardQuery cusQuery = newCacheCondition
//                            .setStartTime(Optional.ofNullable(cacheCondition.getStartTime()).orElse(query.getStartTime()))
//                            .setNumberPulses(Optional.ofNullable(cacheCondition.getNumberPulses()).orElse(query.getNumberPulses()))
//                            .setDeviceId(i).setStartSecond(query.getStartSecond()).setEndSecond(query.getEndSecond());
//                    List<CountDashboardVo> countDashboardVos = deviceProduceLogMapper.countDashboard(cusQuery);
//                    // 整合自定义查询数据
//                    deviceIdDataMap.put(i, new CountDashboardVo().setTotalNum(0L).setNumOfHour(0L).setStartTime(cusQuery.getStartTime()).setNumberPulses(cusQuery.getNumberPulses()));
//                    if (Objects.nonNull(countDashboardVos) && countDashboardVos.size() == 1) {
//                        long hours = DateUtil.between(cusQuery.getStartTime(), cusQuery.getEndTime(), DateUnit.HOUR);
//                        CountDashboardVo countDashboardVo = countDashboardVos.get(0).setNumberPulses(cusQuery.getNumberPulses()).setStartTime(cusQuery.getStartTime());
//                        if (countDashboardVo.getNumberPulses() == 0) {
//                            countDashboardVo.setNumberPulses(0).setTotalNum(0L);
//                        } else {
//                            countDashboardVo.setTotalNum(countDashboardVo.getTotalNum() * countDashboardVo.getNumberPulses());
//                            countDashboardVo.setNumOfHour(hours == 0 ? 0L : countDashboardVo.getTotalNum() / hours);
//                        }
//                        deviceIdDataMap.put(i, countDashboardVo);
//                    }
//                } else {
//                    defaultDeviceCondition.add(i);
//                }
//            });

            // 默认查询数据
            if (!CollectionUtils.isEmpty(defaultDeviceCondition)) {
                query.setDeviceIds(defaultDeviceCondition);
                long hours = DateUtil.between(query.getStartTime(), query.getEndTime(), DateUnit.HOUR);
                //获取设备工作时间
                List<CountDashboardVo> countData = deviceProduceLogMapper.countDashboard(query);
                countData.forEach(i -> {
                    i.setStartTime(query.getStartTime()).setNumberPulses(query.getNumberPulses());
                    if (query.getNumberPulses() == 0) {
                        i.setNumberPulses(0).setTotalNum(0L);
                    } else {
                        i.setTotalNum(i.getTotalNum() * query.getNumberPulses());
                        i.setNumOfHour(hours == 0 ? 0L : i.getTotalNum() / hours).setNumberPulses(query.getNumberPulses());
                    }
                    deviceIdDataMap.put(i.getDeviceId(), i);
                });
            }

            //整合返回数据
            data.getRecords().forEach(i -> {
                i.setTotalNum(0L).setNumOfHour(0L);
                CountDashboardVo countDashboardVo = deviceIdDataMap.get(i.getDeviceId());
                if (Objects.nonNull(countDashboardVo)) {
                    i.setTotalNum(countDashboardVo.getTotalNum()).setNumOfHour(countDashboardVo.getNumOfHour())
                            .setNumberPulses(countDashboardVo.getNumberPulses()).setStartTime(countDashboardVo.getStartTime());
                } else {
                    i.setNumberPulses(query.getNumberPulses());
                }
            });
        }
        return data;
    }

    /**
     * 计数报表
     */
    public Page<CountReportVo> countReport(Page<DeviceProduceLog> page, CountDashboardQuery query) {
        return deviceProduceLogMapper.countReport(page, query);
    }

    /**
     * 小时计数数据
     */
    public List<CountReportVo> hourCountReport(CountDashboardQuery query) {
        return deviceProduceLogMapper.hourCountReport(query);
    }

    /**
     * 获得最新的计数数据
     */
    public DeviceProduceLog getLastByDeviceId(Long deviceId) {
        LambdaQueryWrapper<DeviceProduceLog> lastQW = new LambdaQueryWrapper<DeviceProduceLog>().eq(DeviceProduceLog::getDeviceId, deviceId)
                .orderByDesc(DeviceProduceLog::getCreateTime).last("LIMIT 1");
        return Optional.ofNullable(this.getOne(lastQW)).orElse(new DeviceProduceLog().setCount(-1L));
    }
}
